home *** CD-ROM | disk | FTP | other *** search
/ Best of Shareware / Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso / mac / ZIPPED / DOS / GRAPHICS / POVSRC.ZIP / MISC.ZIP / PORTGUID.TXT < prev    next >
Text File  |  1992-04-17  |  12KB  |  266 lines

  1. Portability Guidelines for POV-Ray by David Buck
  2. -------------------------------------------------
  3.  
  4. In my experiences with DKBTrace, I've found that there are several principles
  5. which should be followed in order to make the code more portable between
  6. systems.  In the interest of making POV-Ray as portable as possible, I've
  7. decided to put some of these principles into writing in order to help others
  8. who are developing code.
  9.  
  10. This guide is divided into two parts.  The first part gives some general
  11. guidelines for making any program more portable from system to system.
  12. The second part describes a specific proposal for making POVRay and other
  13. programs such as GUI's portable.
  14.  
  15.  
  16. General Portability Guidelines
  17. ------------------------------
  18.  
  19. Keep in mind that not all compilers are ANSI compliant.  Many only support the
  20. original K&R specification.
  21.  
  22.   1) Don't call functions or use variables that are system-specific.  This may
  23.      only be done in the system-specific C module.  This is rather obvious,
  24.      but it's worth mentioning.
  25.  
  26.   2) Don't use conditional compiling in the core of the raytracer.  The only
  27.      places where conditional compilation is acceptable is in frame.h in
  28.      order to define defaults for #define'd values, in the config.h file,
  29.      and in the system specific C file (and even then, it shouldn't be
  30.      necessary.)
  31.  
  32.   3) Be careful about ints.  It's usually best to specify short or long.
  33.      Not all ints are the same size.
  34.  
  35.   4) On many systems, the toupper and tolower functions only work properly if
  36.      the parameters are already lowercase or uppercase respectively.  Always
  37.      put a test before these calls when converting the case:
  38.  
  39.         if (isupper(c))
  40.            c = tolower(c);
  41.  
  42.   5) When declaring external functions or variables in a .h file, always
  43.      put the keyword "extern" in front of the definition.  Many C compilers
  44.      will choke on multiply declared identifiers otherwise.
  45.  
  46.   6) Always use the old pre-ANSI parameter declaration mechanism
  47.       i.e.,
  48.             int junk (a,b,c)
  49.                 DBL a;
  50.                 int b;
  51.                 int *c;
  52.                 {...
  53.  
  54.   7) Don't use (void) as a function parameter.  If you do this, put PARAMS
  55.      around the definition:
  56.  
  57.            int junk PARAMS((void)))
  58.  
  59.   8) Don't take the address of an array using the & operator.  Use the name
  60.      of the array itself.
  61.  
  62.       eg.
  63.            int x[10];
  64.  
  65.            junk(x);    is ok, but   junk(&x) is not.
  66.  
  67.   9) Avoid using pre-defined words or names of library functions as variable
  68.      names.  The following are not acceptable as variable names:
  69.        max, min, abs, system
  70.  
  71.  10) When declaring a large amount of space, it's best to malloc it instead
  72.      of declaring it directly.  Some systems have trouble with large objects
  73.      allocated staticly.
  74.  
  75.  11) When including header files, don't put in any pathname or subdirectory
  76.      name (except possibly in system-specific modules.)  Not all systems have
  77.      the same characters for pathname separators.
  78.  
  79.  12) When declaring variables to hold values from 0 to 255, use unsigned char.
  80.      Don't use "char".  This is especially true when representing colors.
  81.      Some systems set the top bit of chars to 0 all the time.  Using unsigned
  82.      chars are ok.
  83.  
  84.  13) When declaring non-static functions (except in system-specific modules),
  85.      always add a prototype for the function in the povproto.h file.  For system
  86.      specific modules, you should include the prototypes at the top of the
  87.      system-specific file.
  88.  
  89.  14) When declaring prototypes, always use the PARAMS macro.
  90.  
  91.  15) Don't declare identifiers longer than 32 characters.  Many systems break
  92.      at that limit.  In fact, some compilers break after 8 characters.  I
  93.      don't intend to compensate for those compilers.
  94.  
  95.  16) Never assume byte ordering.  For example, if you want to take a short and
  96.      output it as two bytes, use "% 256" and "/ 256".  You should be able to
  97.      use "&" and ">>", but don't play tricks with pointers.
  98.  
  99.        eg.
  100.          Bad:
  101.             short x;
  102.  
  103.             putchar (*(unsigned char *)x);
  104.             putchar (*((unsigned char *)x+1));
  105.  
  106.          Good:
  107.             short x;
  108.  
  109.             putchar (x/256);
  110.             putchar (x%256);
  111.  
  112.          Good:
  113.             short x;
  114.  
  115.             putchar (x & 0xFF);
  116.             putchar ((x >> 8) & 0xFF);
  117.  
  118.      Be especially careful with fwrite's:
  119.          fwrite (file, x, 2);
  120.  
  121.  17) Don't assume that all systems can handle vt100 control characters.  It's
  122.      best to use standard text for output.  Don't try to be fancy and change
  123.      colors, underlining, etc. on screen output.  At the very least, provide
  124.      a way of turning it off with a command line option.  As it turns out,
  125.      some systems (read Mac) don't support standard output or command-line
  126.      parameters.  Fortunately, we can get around those.
  127.  
  128.  18) If you really need to create temporary files, be sure to delete them
  129.      when you are finished.  Don't assume that you can just overwrite the
  130.      files when the program runs another time.  Some systems (Vax) store
  131.      several versions of files around and these can take up a lot of space.
  132.      As a rule of thumb, it's best to avoid temporary files if at all possible.
  133.      They make it difficult for multi-tasking systems to run more than one
  134.      session of the program at any one time.
  135.  
  136.  19) Avoid enums.  Not all compilers have them and those that do are very
  137.      inconsistent about their usage.  Many won't allow you to convert enums
  138.      to ints and others won't allow you to switch on an enum.  Stick with
  139.      #define's.  It's harder to manage, but it saves on complaints afterwards.
  140.  
  141.  20) If you encounter a major error and must exit the program, be sure to
  142.      call close_all first.  Some systems have to close windows, screens, etc.
  143.      before exiting.
  144.  
  145.  21) All C files must include "config.h". This is required for many systems
  146.      that need to override missing system functions with #defines.
  147.  
  148.  22) Never assume you know the size of an int or a pointer.  Always use sizeof
  149.      to determine the size.
  150.  
  151.  22) When compiling, use as many error checking options as possible.  Many
  152.      systems warn about unused variables, variables used before set, 
  153.      missing prototypes, etc.  The more of these you can catch yourself, the
  154.      better.
  155.  
  156.  23) Avoid closing and re-opening a file frequently. On some systems, this
  157.      causes disk head thrashing.  You should at least provide a command-line
  158.      option to disable this.
  159.  
  160.  24) Don't pass structure parameters.  Pass pointers to the structures
  161.      instead.  Most compilers these days can handle structure copies, but
  162.      not many handle structure parameters.
  163.  
  164.  25) When reading or writing binary files, always open them with the "b"
  165.      option.  Otherwise, many systems will discard '\0' characters and perform
  166.      translations on CR's and LF's.
  167.  
  168.       eg.
  169.           f = fopen ("filename", "wb");
  170.  
  171.  
  172. POV-Ray Portable Graphics Proposal
  173. -----------------------------------
  174.  
  175. The problem of making a portable graphics program is a difficult one.  In many
  176. ways, POV-Ray itself is easy to port because the only real graphics primitive
  177. required is one to draw a point of a certain color at a certain x,y coordinate.
  178. The coordinates are guaranteed to proceed from left to right, top to bottom.
  179. (Incidently, the left-to-right ordering is assumed by the Amiga drivers.)
  180.  
  181. The problem of making a more general interface for something more complex
  182. such as a GUI is dramatically more difficult.  Most systems provide routines
  183. to draw lines, circles, etc. on the screen.  Some (eg. Amiga), have special
  184. hardware to do this.  On some systems, third party boards have such primitives.
  185. Even the more complex operations are provided in hardware on some systems.
  186. Silicon Graphics Iris workstations, for example, have hardware support for
  187. Gouraud-shaded filled polygons.
  188.  
  189. Our strategy should follow some common principles:
  190.  
  191.    1) It should be easy to use from an application level.  Application programs
  192.       shouldn't need to care about the type of system they're running on.
  193.    2) It should be able to use any number of colors in your palette from
  194.       2 colors to 256.  Support for 24 bit color should also be available.
  195.    3) People who port the code should be able to provide their own low-level
  196.       routines to handle their particular graphics system.
  197.    4) If a particular system has special hardware that could speed up certain
  198.       operations, the person porting the code should be able to use it easily.
  199.    5) Simple ports should be possible by providing only the basic required
  200.       functions.  The port can be made faster if more primitives are
  201.       implemented specifically for that system.
  202.  
  203.  
  204. Here's my proposal:
  205.  
  206. Consider the following system diagram:
  207.  
  208.                             -----------------
  209.                             |               |
  210.                             |  Applications |
  211.                             |               |
  212.                             -----------------
  213.                                     |
  214.                                     |
  215.                                     |
  216.                                     |
  217.                -------------------  |
  218.                |                 |  |   ------------------
  219.                | System-specific |  |   |                |
  220.                |    Functions    |  |   | Non-primitives |
  221.                |                 |  |   |                |
  222.                -------------------  |   ------------------
  223.                                |    |    |
  224.                                |    |    |
  225.                                |    |    |
  226.                             -----------------
  227.                             |               |
  228.                             |    Function   |
  229.                             |   Variables   |
  230.                             |               |
  231.                             -----------------
  232.  
  233. In this diagram, the applications will perform their operations by calling
  234. function variables.  This would probably be simplified by providing macros to
  235. perform the actual calls.
  236.  
  237. When the application starts, it calls two initialization functions:
  238.  
  239.    pov_init_gfx_defaults();
  240.    pov_init_gfx_system_specific();
  241.  
  242. The call to pov_init_gfx_defaults() will call a function in the non-primitives
  243. area to bind default functions to all of the function variables in the base
  244. module.  The subsequent call to pov_init_gfx_system_specific() will call a function
  245. in the system-specific area to over-ride functions bound in by the
  246. non-primitive area with functions that work for that specific system.
  247.  
  248. For example, if we had a draw_line function we could write a non-primitive
  249. function to perform draw_filled_polygon().  This function would be bound to the
  250. appropriate function variable when the non-primitive area is initialized.
  251.  
  252. If your particular hardware has hardware support for draw_filled_polygon(), then
  253. you can bind in your own function in the system-specific area to perform the
  254. same action.
  255.  
  256. Sometimes, the system-specific function will want to perform its own work in
  257. addition to the work done by the non-primitive function.  In this case, the
  258. system function will store away a copy of the function pointer before it over-
  259. writes it with its own.  In its own function, it will call the stored function
  260. pointer in addition to performing its own operations.
  261.  
  262. The system-specific functions can call other system-specific functions
  263. directly if they desire (although this is not recommended.)  The applications
  264. and the non-primitives must make their calls through the function variables.
  265.  
  266.